#pragma once

#include <mcp/config.h>
#include <mcp/forward.h>
#include <mcp/types.h>
#include <mcp/error.h>

#include <memory>
#include <string>
#include <vector>
#include <functional>
#include <coroutine>

namespace mcp {
namespace transport {

/// @brief Transport event types
enum class EventType {
    Message,
    Error,
    Close,
    Open
};

/// @brief Transport event structure
struct TransportEvent {
    EventType type;
    std::variant<json::Value, Error> data;
};

/// @brief Message handler function type
using MessageHandler = std::function<void(const json::Value&)>;
using ErrorHandler = std::function<void(const Error&)>;
using CloseHandler = std::function<void()>;
using OpenHandler = std::function<void()>;

/// @brief Base transport interface
class Transport {
public:
    Transport() = default;
    virtual ~Transport() = default;

    // Disable copying
    Transport(const Transport&) = delete;
    Transport& operator=(const Transport&) = delete;

    /// @brief Start the transport
    /// @return true if started successfully, false otherwise
    virtual bool start() = 0;

    /// @brief Stop the transport
    virtual void stop() = 0;

    /// @brief Check if transport is connected
    /// @return true if connected, false otherwise
    virtual bool is_connected() const = 0;

    /// @brief Send a message
    /// @param message Message to send
    /// @return true if sent successfully, false otherwise
    virtual bool send(const json::Value& message) = 0;

    /// @brief Send a message asynchronously
    /// @param message Message to send
    /// @return Coroutine handle for the operation
    virtual std::coroutine_handle<> send_async(const json::Value& message) = 0;

    /// @brief Set message handler
    /// @param handler Function to handle incoming messages
    virtual void set_message_handler(MessageHandler handler) = 0;

    /// @brief Set error handler
    /// @param handler Function to handle transport errors
    virtual void set_error_handler(ErrorHandler handler) = 0;

    /// @brief Set close handler
    /// @param handler Function to handle transport close
    virtual void set_close_handler(CloseHandler handler) = 0;

    /// @brief Set open handler
    /// @param handler Function to handle transport open
    virtual void set_open_handler(OpenHandler handler) = 0;

    /// @brief Get transport type
    /// @return String identifying the transport type
    virtual std::string get_type() const = 0;

    /// @brief Get transport capabilities
    /// @return JSON object describing transport capabilities
    virtual json::Value get_capabilities() const = 0;
};

/// @brief Transport factory interface
class TransportFactory {
public:
    virtual ~TransportFactory() = default;

    /// @brief Create a new transport instance
    /// @return Unique pointer to transport instance
    virtual std::unique_ptr<Transport> create() = 0;

    /// @brief Get transport type
    /// @return String identifying the transport type
    virtual std::string get_type() const = 0;

    /// @brief Get supported schemes
    /// @return List of URL schemes supported by this transport
    virtual std::vector<std::string> get_supported_schemes() const = 0;
};

/// @brief Transport registry for managing transport types
class TransportRegistry {
public:
    static TransportRegistry& instance();

    /// @brief Register a transport factory
    /// @param factory Transport factory to register
    void register_factory(std::shared_ptr<TransportFactory> factory);

    /// @brief Unregister a transport factory
    /// @param type Transport type to unregister
    void unregister_factory(const std::string& type);

    /// @brief Create transport by type
    /// @param type Transport type
    /// @return Transport instance or nullptr if type not found
    std::unique_ptr<Transport> create_transport(const std::string& type);

    /// @brief Create transport by URL
    /// @param url URL to create transport from
    /// @return Transport instance or nullptr if URL scheme not supported
    std::unique_ptr<Transport> create_transport_from_url(const std::string& url);

    /// @brief Get registered transport types
    /// @return List of registered transport types
    std::vector<std::string> get_registered_types() const;

    /// @brief Check if transport type is supported
    /// @param type Transport type to check
    /// @return true if supported, false otherwise
    bool is_supported(const std::string& type) const;

private:
    struct Impl;
    std::unique_ptr<Impl> impl_;
    TransportRegistry();
};

} // namespace transport
} // namespace mcp